package com.ljh.onlinetest.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ljh.onlinetest.domain.ExamPaper;
import com.ljh.onlinetest.domain.Question;
import com.ljh.onlinetest.domain.TextContent;
import com.ljh.onlinetest.domain.User;
import com.ljh.onlinetest.domain.enums.ExamPaperTypeEnum;
import com.ljh.onlinetest.domain.exam.ExamPaperQuestionItemObject;
import com.ljh.onlinetest.domain.exam.ExamPaperTitleItemObject;
import com.ljh.onlinetest.repository.ExamPaperMapper;
import com.ljh.onlinetest.repository.QuestionMapper;
import com.ljh.onlinetest.service.ExamPaperService;
import com.ljh.onlinetest.service.QuestionService;
import com.ljh.onlinetest.service.SubjectService;
import com.ljh.onlinetest.service.TextContentService;
import com.ljh.onlinetest.service.enums.ActionEnum;
import com.ljh.onlinetest.utils.DateTimeUtil;
import com.ljh.onlinetest.utils.ExamUtil;
import com.ljh.onlinetest.utils.JsonUtil;
import com.ljh.onlinetest.utils.ModelMapperSingle;
import com.ljh.onlinetest.viewmodel.admin.paper.PaperEditRequestVM;
import com.ljh.onlinetest.viewmodel.admin.paper.PaperPageRequestVM;
import com.ljh.onlinetest.viewmodel.admin.paper.PaperTitleItemVM;
import com.ljh.onlinetest.viewmodel.admin.question.QuestionEditRequestVM;
import com.ljh.onlinetest.viewmodel.student.dashboard.PaperFilter;
import com.ljh.onlinetest.viewmodel.student.dashboard.PaperInfo;
import com.ljh.onlinetest.viewmodel.student.exam.ExamPaperPageVM;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author ljh
 * @ClassName ExamPaperServiceImpl.java
 * @createTime 2022年01月18日
 */
@Service
public class ExamPaperServiceImpl extends BaseServiceImpl<ExamPaper> implements ExamPaperService {

    protected final static ModelMapper modelMapper = ModelMapperSingle.Instance();
    private ExamPaperMapper examPaperMapper;
    private QuestionMapper questionMapper;
    private TextContentService textContentService;
    private QuestionService questionService;
    private SubjectService subjectService;


    @Autowired
    public ExamPaperServiceImpl(ExamPaperMapper examPaperMapper, QuestionMapper questionMapper, TextContentService textContentService, QuestionService questionService, SubjectService subjectService) {
        super(examPaperMapper);
        this.examPaperMapper = examPaperMapper;
        this.questionMapper = questionMapper;
        this.textContentService = textContentService;
        this.questionService = questionService;
        this.subjectService = subjectService;
    }

    @Override
    public PageInfo<ExamPaper> listPage(PaperPageRequestVM pageRequestVM) {
        return PageHelper.startPage(pageRequestVM.getPageIndex(),pageRequestVM.getPageSize(),"id desc").doSelectPageInfo(() ->
                examPaperMapper.page(pageRequestVM)
        );
    }

    @Override
    public PaperEditRequestVM examPaperToVM(Integer id) {
        ExamPaper examPaper = examPaperMapper.selectByPrimaryKey(id);
        return examPaperToVM(examPaper);
    }

    @Override
    public PaperEditRequestVM examPaperToVM(ExamPaper examPaper) {
        PaperEditRequestVM vm = modelMapper.map(examPaper, PaperEditRequestVM.class);
        vm.setLevel(examPaper.getGradeLevel());
        TextContent textContent = textContentService.selectById(examPaper.getFrameTextContentId());
        List<ExamPaperTitleItemObject> paperTitleItems = JsonUtil.toJsonListObject(textContent.getContent(),ExamPaperTitleItemObject.class);
        List<Integer> questionIds = paperTitleItems.stream().flatMap(t ->
            t.getQuestionItems().stream().map(q -> q.getId())
        ).collect(Collectors.toList());
        List<Question> questions = questionMapper.selectByIds(questionIds);
        List<PaperTitleItemVM> examPaperTitleItemVMS = paperTitleItems.stream().map(t -> {
            PaperTitleItemVM paperTitleItemVM = modelMapper.map(t,PaperTitleItemVM.class);
            List<QuestionEditRequestVM> questionItemsVM = t.getQuestionItems().stream().map(i -> {
                Question question = questions.stream().filter(q -> q.getId().equals(i.getId())).findFirst().get();
                QuestionEditRequestVM questionEditRequestVM = questionService.getQuestionEditRequestVM(question);
                questionEditRequestVM.setItemOrder(i.getItemOrder());
                return questionEditRequestVM;
            }).collect(Collectors.toList());
            //设置题型和题目内容
            paperTitleItemVM.setQuestionItems(questionItemsVM);
            return paperTitleItemVM;
        }).collect(Collectors.toList());
        vm.setTitleItems(examPaperTitleItemVMS);
        vm.setScore(ExamUtil.scoreToVM(examPaper.getScore()));
        if (ExamPaperTypeEnum.TimeLimit == ExamPaperTypeEnum.fromCode(examPaper.getPaperType())){
            List<String> limitDateTime = Arrays.asList(DateTimeUtil.dateFormat(examPaper.getLimitStartTime()),DateTimeUtil.dateFormat(examPaper.getLimitEndTime()));
            vm.setLimitDateTime(limitDateTime);
        }
        return vm;
    }

    @Override
    @Transactional
    public ExamPaper savePaperFromVM(PaperEditRequestVM model, User currentUser) {
        ActionEnum actionEnum = model.getId() == null ? ActionEnum.ADD : ActionEnum.UPDATE;
        Date date = new Date();
        List<PaperTitleItemVM> titleItemVMList = model.getTitleItems();
        List<ExamPaperTitleItemObject> paperTitleItemObjectList= frameTextContentFromVM(titleItemVMList);
        String frameTextContentStr = JsonUtil.toJsonStr(paperTitleItemObjectList);
        ExamPaper examPaper;
        //添加
        if (actionEnum == ActionEnum.ADD){
            examPaper = modelMapper.map(model, ExamPaper.class);
            TextContent textContent = new TextContent(frameTextContentStr, date);
            textContentService.insertByFilter(textContent);
            examPaper.setFrameTextContentId(textContent.getId());
            examPaper.setCreateTime(date);
            examPaper.setCreateUser(currentUser.getId());
            examPaper.setDeleted(false);
            examPaperFromVM(model,examPaper,titleItemVMList);
            examPaperMapper.insertSelective(examPaper);
        } else {//修改
            examPaper = examPaperMapper.selectByPrimaryKey(model.getId());
            TextContent textContent = textContentService.selectById(examPaper.getFrameTextContentId());
            textContent.setContent(frameTextContentStr);
            textContentService.updateByIdFilter(textContent);
            modelMapper.map(model,ExamPaper.class);
            examPaperFromVM(model,examPaper,titleItemVMList);
            examPaperMapper.updateByPrimaryKeySelective(examPaper);
        }
        return examPaper;
    }

    @Override
    public PageInfo<ExamPaper> taskExamPage(PaperPageRequestVM pageRequestVM) {
        return PageHelper.startPage(pageRequestVM.getPageIndex(),pageRequestVM.getPageSize(),"id desc").doSelectPageInfo(() -> {
            examPaperMapper.taskExamPage(pageRequestVM);
        });
    }

    @Override
    public Integer selectAllCount() {
        return examPaperMapper.selectAllCount();
    }

    @Override
    public List<PaperInfo> indexPaper(PaperFilter fixPaperFilter) {
        return examPaperMapper.indexPaper(fixPaperFilter);
    }

    @Override
    public PageInfo<ExamPaper> studentPage(ExamPaperPageVM model) {
        return PageHelper.startPage(model.getPageIndex(),model.getPageSize(),"id desc").doSelectPageInfo(() -> {
            examPaperMapper.studentPage(model);
        });
    }

    /**
     * @param titleItemVMList
     * @return
     * 将题目vm列表转成TitleItemObject列表
     */
    private List<ExamPaperTitleItemObject> frameTextContentFromVM(List<PaperTitleItemVM> titleItemVMList) {
        AtomicInteger index = new AtomicInteger(1);
        return titleItemVMList.stream().map(t -> {
            ExamPaperTitleItemObject titleItemObject = modelMapper.map(t, ExamPaperTitleItemObject.class);
            List<ExamPaperQuestionItemObject> questionItemObjects = t.getQuestionItems().stream().map(q -> {
                ExamPaperQuestionItemObject questionItemObject = modelMapper.map(q, ExamPaperQuestionItemObject.class);
                questionItemObject.setItemOrder(index.getAndIncrement());
                return questionItemObject;
            }).collect(Collectors.toList());
            titleItemObject.setQuestionItems(questionItemObjects);
            return titleItemObject;
        }).collect(Collectors.toList());
    }

    /**
     * @param model 前端传递的vm
     * @param examPaper
     * @param titleItemVMList vm里面的题目vm列表
     * 根据试卷VM以及试卷VM里的题目vm列表，来设置examPaper的年级gradeLevel，分数score，题目数questionCount，limitStartTime ,limitEndTime等字段。
     */
    private void examPaperFromVM(PaperEditRequestVM model, ExamPaper examPaper, List<PaperTitleItemVM> titleItemVMList) {
        Integer gradeLevel = subjectService.levelBySubjectId(model.getSubjectId());
        int questionCount = titleItemVMList.stream().mapToInt(t -> t.getQuestionItems().size()).sum();
        int score = titleItemVMList.stream().flatMapToInt(t -> t.getQuestionItems().stream()
                .mapToInt(q -> ExamUtil.scoreFromVM(q.getScore()))
        ).sum();
        examPaper.setGradeLevel(gradeLevel);
        examPaper.setScore(score);
        examPaper.setQuestionCount(questionCount);
        List<String> limitDateTime = model.getLimitDateTime();
        if (ExamPaperTypeEnum.TimeLimit == ExamPaperTypeEnum.fromCode(examPaper.getPaperType())){
            examPaper.setLimitStartTime(DateTimeUtil.parse(limitDateTime.get(0),DateTimeUtil.STANDER_FORMAT));
            examPaper.setLimitEndTime(DateTimeUtil.parse(limitDateTime.get(1),DateTimeUtil.STANDER_FORMAT));
        }
    }


}
